﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Missbot.Common;
using MongoDB.Driver;

namespace Missbot.Service
{
    /// <summary>
    /// Mongodb服务
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class MongoService<T> where T : DbBaseEntity
    {
        private static MongoContext Repo => AutofacSvc.Resolve<MongoContext>();

        /// <summary>
        /// 获取集合（表）
        /// </summary>
        /// <returns></returns>
        public static IMongoCollection<T> GetCollection(string tableName = null)
        {
            return Repo.Collection<T>(tableName);
        }

        /// <summary>
        /// 强类型查询（适用精确查询）
        /// 查询条件包含可为空的时间类型字段时：只能查询有无值
        /// </summary>
        /// <param name="exp"></param>
        /// <returns></returns>
        public static List<T> Get(Expression<Func<T, bool>> exp)
        {
            return GetCollection().Find(exp).ToList();
        }

        /// <summary>
        /// 获取记录列表
        /// </summary>
        /// <param name="findExp"></param>
        /// <param name="sortExp"></param>
        /// <param name="isAscending"></param>
        /// <param name="skip"></param>
        /// <param name="limit"></param>
        /// <returns></returns>
        public static List<T> Get(Expression<Func<T, bool>> findExp, Expression<Func<T, object>> sortExp, bool isAscending = true, int skip = 0, int limit = 0)
        {
            var fluent = GetCollection().Find(findExp);

            var sortBuilder = Builders<T>.Sort;
            var sortDef = isAscending ? sortBuilder.Ascending(sortExp) : sortBuilder.Descending(sortExp);
            fluent = fluent.Sort(sortDef);

            if (skip != 0)
            {
                fluent = fluent.Skip(skip);
            }

            if (limit != 0)
            {
                fluent = fluent.Limit(limit);
            }

            return fluent.ToList();
        }

        /// <summary>
        /// 获取记录列表
        /// </summary>
        /// <param name="filter"></param>
        /// <param name="sortExp"></param>
        /// <param name="isAscending"></param>
        /// <param name="skip"></param>
        /// <param name="limit"></param>
        /// <returns></returns>
        public static List<T> Get(FilterDefinition<T> filter, Expression<Func<T, object>> sortExp, bool isAscending = true, int skip = 0, int limit = 0)
        {
            var fluent = GetCollection().Find(filter);

            var sortBuilder = Builders<T>.Sort;
            var sortDef = isAscending ? sortBuilder.Ascending(sortExp) : sortBuilder.Descending(sortExp);
            fluent = fluent.Sort(sortDef);

            if (skip != 0)
            {
                fluent = fluent.Skip(skip);
            }

            if (limit != 0)
            {
                fluent = fluent.Limit(limit);
            }

            return fluent.ToList();
        }

        /// <summary>
        /// 获取记录列表
        /// </summary>
        /// <returns></returns>
        public static List<T> Get()
        {
            return Get(p => true);
        }

        /// <summary>
        /// 获取唯一一条记录
        /// </summary>
        /// <param name="exp"></param>
        /// <returns></returns>
        public static T GetOnly(Expression<Func<T, bool>> exp)
        {
            return Get(exp).FirstOrDefault();
        }

        /// <summary>
        /// 获取唯一一条记录
        /// </summary>
        /// <param name="findExp"></param>
        /// <param name="sortExp"></param>
        /// <param name="isAscending"></param>
        /// <param name="skip"></param>
        /// <returns></returns>
        public static T GetOnly(Expression<Func<T, bool>> findExp, Expression<Func<T, object>> sortExp, bool isAscending = true, int skip = 0)
        {
            return Get(findExp, sortExp, isAscending, skip, 1).FirstOrDefault();
        }

        /// <summary>
        /// 获取记录总数
        /// </summary>
        /// <param name="exp"></param>
        /// <returns></returns>
        public static long Count(Expression<Func<T, bool>> exp)
        {
            return GetCollection().CountDocuments(exp);
        }

        /// <summary>
        /// 获取记录总数
        /// </summary>
        /// <returns></returns>
        public static long Count()
        {
            return Count(p => true);
        }

        /// <summary>
        /// 是否有满足条件的记录
        /// </summary>
        /// <param name="exp"></param>
        /// <returns></returns>
        public static bool Any(Expression<Func<T, bool>> exp = null)
        {
            return exp == null ? Count() > 0 : Count(exp) > 0;
        }

        /// <summary>
        /// 插入
        /// </summary>
        /// <param name="entity"></param>
        public static void Insert(T entity)
        {
            entity.Id = MongoDB.Bson.ObjectId.GenerateNewId().ToString();
            GetCollection().InsertOne(entity);
        }

        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="entity"></param>
        public static void Update(T entity)
        {
            var filter = Builders<T>.Filter.Eq(e => e.Id, entity.Id);
            GetCollection().ReplaceOne(filter, entity);
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="entity"></param>
        public static void Delete(T entity)
        {
            GetCollection().DeleteOne(e => e.Id == entity.Id);
        }

        /// <summary>
        /// 批量删除
        /// </summary>
        /// <param name="where"></param>
        public static long DeleteMany(Expression<Func<T, bool>> where)
        {
            return GetCollection().DeleteMany(where).DeletedCount;
        }

        /// <summary>
        /// 批量删除
        /// </summary>
        /// <param name="entities"></param>
        public static void DeleteMany(IEnumerable<T> entities)
        {
            foreach (var entity in entities)
            {
                Delete(entity);
            }
        }
    }
}